package com.mxpio.erp.workshop.policy.impl;

import com.mxpio.erp.common.LotStatusUtil;
import com.mxpio.erp.common.enums.ItemEnums;
import com.mxpio.erp.common.enums.NoticeStatusEnums;
import com.mxpio.erp.common.enums.OrderEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.inventory.entity.*;
import com.mxpio.erp.common.jpa.entity.BizNoticeType;
import com.mxpio.erp.common.jpa.model.LotKey;
import com.mxpio.erp.common.jpa.model.Notice;
import com.mxpio.erp.common.jpa.model.NoticeLine;
import com.mxpio.erp.common.order.policy.AbstractNoticePolicy;
import com.mxpio.erp.common.order.policy.NoticeContext;
import com.mxpio.erp.common.purchase.entity.RejectNotice;
import com.mxpio.erp.common.purchase.entity.RejectNoticeLine;
import com.mxpio.erp.common.technology.entity.Item;
import com.mxpio.erp.common.technology.entity.ItemPlanProp;
import com.mxpio.erp.common.vo.OrderExcuteLineVo;
import com.mxpioframework.jpa.JpaUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 生产 领、退、补 料 通知单执行策略（MoPickingNotice通知单执行）
 * @author mxpio
 *
 */
public class DefaultMoPickingNoticePolicy extends AbstractNoticePolicy {

	private List<OrderExcuteLineVo> orderExcuteVos;

	public DefaultMoPickingNoticePolicy(List<OrderExcuteLineVo> orderExcuteVos) {
		this.orderExcuteVos = orderExcuteVos;
	}
	
	@Override
	public void execute(NoticeContext context) {
		
	}

	@Override
	public void apply(NoticeContext context) {
		if(beforeExecute(context)) {
			execute(context);
			Notice notice = context.getEntity();
			List<OrderExcuteLineVo> orderExcuteVos = context.getOrderExcuteVos();

			if (notice.getPickingType().equals(NoticeStatusEnums.NoticeType.MO_M_IN.getCode())){//生产退料"
				//jit物料
				List<OrderExcuteLineVo> jitVos = new ArrayList<>();
				//非jit物料
				List<OrderExcuteLineVo> unJitVos = new ArrayList<>();

				Set<String> itemCodeSet = orderExcuteVos.stream().map(OrderExcuteLineVo::getItemCode).collect(Collectors.toSet());
				List<Item> itemList = JpaUtil.linq(Item.class).in("itemCode", itemCodeSet).list();
				Map<Object, Item> itemMap = JpaUtil.index(itemList, "itemCode");

				List<ItemPlanProp> itemPlanPropList = JpaUtil.linq(ItemPlanProp.class).equal("propType", "item").in("code", itemCodeSet).list();
				Map<String, ItemPlanProp> itemPlanPropMap = JpaUtil.index(itemPlanPropList, "code");
				for(OrderExcuteLineVo vo : orderExcuteVos){
					if (itemPlanPropMap.containsKey(vo.getItemCode())
							&& ItemEnums.FeedingMode.JIT.getTypeCode().equals(itemPlanPropMap.get(vo.getItemCode()).getFeedingMode())){
						jitVos.add(vo);
					}else{
						unJitVos.add(vo);
					}
				}
				if (jitVos.size()>0){
					//0，生成退货入库仓单，且自动执行()
					WarehouseOrder inWo = null;
					int lineNo = 0;
					List<BizNoticeType> bizNoticeTypes = JpaUtil.linq(BizNoticeType.class).list();
					for(OrderExcuteLineVo vo : jitVos){
						lineNo++;
						if(inWo == null){
							inWo = new WarehouseOrder();
							inWo.setAccessType(notice.getAccessType());
							inWo.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());
							inWo.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
							inWo.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());
							inWo.setOrderDate(new Date());
							inWo.setOriginBizNo(vo.getBizOrderNo());
							inWo.setWhCode(vo.getWhCode());
							inWo.setWoType(notice.getPickingType());
							inWo.setOriginNoticeNo(notice.getNoticeNo());//关联noticeno字段
							inWo.setExecuteTime(new Date());
							inWo.setExecutor("8888");//自动化助手，默认指定用户
							JpaUtil.save(inWo);
						}
						WarehouseOrderLine inWoLine = new WarehouseOrderLine();
						inWoLine.setWhCode(inWo.getWhCode());
						inWoLine.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
						Item item = JpaUtil.linq(Item.class).idEqual(vo.getItemCode()).findOne();
						inWoLine.setItemCode(vo.getItemCode());
						inWoLine.setItemGroupCode(item.getItemGroupCode());
						inWoLine.setItemName(item.getItemName());
						inWoLine.setItemSpec(item.getItemSpec());
						inWoLine.setUnitCode(item.getUnitCode());
						inWoLine.setDrawingNo(item.getDrawingNo());
						inWoLine.setQuantity(vo.getQuantity());
						inWoLine.setBizNo(inWo.getBizNo());
						inWoLine.setLineNo(lineNo+"");
						inWoLine.setOriginBizNo(vo.getBizOrderNo());
						inWoLine.setOriginBizLineNo(vo.getBizOrderlineNo());
						inWoLine.setSort(vo.getSort());
						inWoLine.setLotNo(vo.getLotNo());
						inWoLine.setSubLotIndex(vo.getSubLotIndex());
						inWoLine.setOriginNoticeNo(notice.getNoticeNo());
						inWoLine.setOriginNoticeLineNo(vo.getNoticeLineNo());
						JpaUtil.save(inWoLine);

						//自动执行，生成流水
						InvFlow inFlow = new InvFlow();
						inFlow.setAccessType(inWo.getAccessType());
						inFlow.setItemCode(inWoLine.getItemCode());
						inFlow.setWhCode(inWo.getWhCode());
						inFlow.setQuantity(inWoLine.getQuantity());
						inFlow.setMemo(inWo.getMemo());
						inFlow.setOriginBizNo(inWo.getOriginBizNo());
						inFlow.setOriginBizType(inWo.getOriginBizType());
						inFlow.setOriginBizLineNo(inWoLine.getOriginBizLineNo());
						inFlow.setWoBizNo(inWo.getBizNo());
						inFlow.setWoBizType(inWo.getWoType());
						inFlow.setWoBizLineNo(inWoLine.getLineNo());
						inFlow.setLotNo(inWoLine.getLotNo());
						inFlow.setSubLotIndex(inWoLine.getSubLotIndex());//增加子批索引
						JpaUtil.save(inFlow);
					}

					//1，生成采购退货通知单
					for(OrderExcuteLineVo vo : jitVos){
						String lotNo = vo.getLotNo();
						String subLotIndex = vo.getSubLotIndex();
						String originBizNo = "";
						String originBizLineNo = "";
						List<InvFlow> invFlows = JpaUtil.linq(InvFlow.class)
								.equal("lotNo", lotNo)
								.equal("subLotIndex", subLotIndex)
								.equal("woBizType", "10")
								.equal("accessType", "in").list();//考虑常规物料采购入库，后续改为jit物料的情况(追溯源采购订单)
						if (invFlows.size()>0){
							originBizNo = invFlows.get(0).getOriginBizNo();
							originBizLineNo = invFlows.get(0).getOriginBizLineNo();
						}
						List<InvFlow> invFlows2 = JpaUtil.linq(InvFlow.class)
								.equal("lotNo", lotNo)
								.equal("subLotIndex", subLotIndex)
								.equal("woBizType", "57")
								.equal("accessType", "in").list();//查找送货计划产生的入库流水
						if(invFlows2.size()>0){
							originBizNo = invFlows2.get(0).getOriginBizNo();
							originBizLineNo = invFlows2.get(0).getOriginBizLineNo();
						}

						//自动生成退货通知单，
						RejectNotice rejectNotice = new RejectNotice();
						rejectNotice.setBizOrderNo(originBizNo);
						rejectNotice.setNoticeDate(new Date());
						rejectNotice.setWhCode(vo.getWhCode());
						rejectNotice.setAccessType(OrderEnums.AccessType.OUT.getCode());
						rejectNotice.setPickingType(NoticeStatusEnums.NoticeType.PO_OUT.getCode());
						LotKey lotKey = new LotKey();
						lotKey.setLotNo(lotNo);
						lotKey.setSubLotIndex(subLotIndex);
						Lot lot = JpaUtil.getOne(Lot.class, lotKey);
						String rejectType = "";//值对应通知单退货类型字典值
						if (StringUtils.equals(lot.getLotStatus(), LotStatusUtil.toBinaryString("0"))){
							rejectType = "0";//合格品退货
						}else{
							rejectType = "1";//不合格品退货
						}
						rejectNotice.setRejectType(rejectType);
						rejectNotice.setNoticeStatus(NoticeStatusEnums.NoticeStatus.CONFIRM.getStatusCode());

						JpaUtil.save(rejectNotice);

						NoticeLine rejectNoticeLine = new RejectNoticeLine();
						rejectNoticeLine.setOriginBizLineNo(originBizLineNo);
						rejectNoticeLine.setOriginBizNo(originBizNo);
						rejectNoticeLine.setItemCode(vo.getItemCode());
						rejectNoticeLine.setNoticeNo(rejectNotice.getNoticeNo());
						rejectNoticeLine.setQuantity(vo.getQuantity());
						rejectNoticeLine.setLotNo(lot.getLotNo());
						rejectNoticeLine.setSubLotIndex(lot.getSubLotIndex());
						rejectNoticeLine.setLineNo("1");
						Item item = JpaUtil.linq(Item.class).idEqual(vo.getItemCode()).findOne();
						rejectNoticeLine.setItemName(item.getItemName());
						rejectNoticeLine.setItemSpec(item.getItemSpec());
						rejectNoticeLine.setUnitCode(item.getUnitCode());
						rejectNoticeLine.setDrawingNo(item.getDrawingNo());
						JpaUtil.save(rejectNoticeLine);

						//通知单默认确认，自动生成仓单
						WarehouseOrder outWo = new WarehouseOrder();
						outWo.setAccessType(rejectNotice.getAccessType());
						outWo.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());
						outWo.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
						outWo.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());
						outWo.setOrderDate(new Date());
						outWo.setOriginBizNo(rejectNotice.getBizOrderNo());
						outWo.setWhCode(rejectNotice.getWhCode());
						outWo.setWoType(rejectNotice.getPickingType());
						outWo.setOriginNoticeNo(rejectNotice.getNoticeNo());//关联noticeno字段
						outWo.setExecuteTime(new Date());
						outWo.setExecutor("8888");//自动化助手，默认指定用户
						JpaUtil.save(outWo);
						//仓单明细
						WarehouseOrderLine outWoLine = new WarehouseOrderLine();
						outWoLine.setWhCode(outWo.getWhCode());
						outWoLine.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
						outWoLine.setItemCode(rejectNoticeLine.getItemCode());
						outWoLine.setItemGroupCode(item.getItemGroupCode());
						outWoLine.setItemName(item.getItemName());
						outWoLine.setItemSpec(item.getItemSpec());
						outWoLine.setUnitCode(item.getUnitCode());
						outWoLine.setDrawingNo(item.getDrawingNo());
						outWoLine.setQuantity(rejectNoticeLine.getQuantity());
						outWoLine.setBizNo(outWo.getBizNo());
						outWoLine.setLineNo("1");
						outWoLine.setOriginBizNo(rejectNoticeLine.getOriginBizNo());
						outWoLine.setOriginBizLineNo(rejectNoticeLine.getOriginBizLineNo());
						outWoLine.setLotNo(lot.getLotNo());
						outWoLine.setSubLotIndex(lot.getSubLotIndex());
						outWoLine.setOriginNoticeNo(rejectNoticeLine.getNoticeNo());
						outWoLine.setOriginNoticeLineNo(rejectNoticeLine.getLineNo());
						JpaUtil.save(outWoLine);

						//自动执行，生成出流水
						InvFlow outFlow = new InvFlow();
						outFlow.setAccessType(outWo.getAccessType());
						outFlow.setItemCode(outWoLine.getItemCode());
						outFlow.setWhCode(outWo.getWhCode());
						outFlow.setQuantity(outWoLine.getQuantity());
						outFlow.setMemo(outWo.getMemo());
						outFlow.setOriginBizNo(outWo.getOriginBizNo());
						outFlow.setOriginBizType(outWo.getOriginBizType());
						outFlow.setOriginBizLineNo(outWoLine.getOriginBizLineNo());
						outFlow.setWoBizNo(outWo.getBizNo());
						outFlow.setWoBizType(outWo.getWoType());
						outFlow.setWoBizLineNo(outWoLine.getLineNo());
						outFlow.setLotNo(outWoLine.getLotNo());
						outFlow.setSubLotIndex(outWoLine.getSubLotIndex());//增加子批索引
						JpaUtil.save(outFlow);
					}
				}

				if (unJitVos.size()>0){
					WarehouseOrder wo = null;
					int lineNo = 0;
					List<BizNoticeType> bizNoticeTypes = JpaUtil.linq(BizNoticeType.class).list();
					Map<String, BizNoticeType> typesMap = JpaUtil.index(bizNoticeTypes);
					for(OrderExcuteLineVo vo : unJitVos){
						lineNo++;
						if(wo == null){
							wo = new WarehouseOrder();
							wo.setAccessType(notice.getAccessType());
							wo.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());
							wo.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
							wo.setOrderStatus(OrderStatusEnums.OrderStatus.PLAN.getStatusCode());
							wo.setOrderDate(new Date());
							wo.setOriginBizNo(StringUtils.isBlank(vo.getBizOrderNo())?vo.getNoticeNo():vo.getBizOrderNo());//20221012 wpp 如果是由手工录入的通知单（物资系统操作），那么此处bizOrderNo会为空
							wo.setWhCode(vo.getWhCode());
							wo.setWoType(notice.getPickingType());
							wo.setOriginNoticeNo(notice.getNoticeNo());//关联noticeno字段
							JpaUtil.save(wo);
						}
						WarehouseOrderLine line = new WarehouseOrderLine();
						line.setWhCode(wo.getWhCode());
						line.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
						Item item = JpaUtil.linq(Item.class).idEqual(vo.getItemCode()).findOne();
						line.setItemCode(vo.getItemCode());
						line.setItemGroupCode(item.getItemGroupCode());
						line.setItemName(item.getItemName());
						line.setItemSpec(item.getItemSpec());
						line.setUnitCode(item.getUnitCode());
						line.setDrawingNo(item.getDrawingNo());
						line.setQuantity(vo.getQuantity());
						line.setBizNo(wo.getBizNo());
						line.setLineNo(lineNo+"");
						//line.setOriginBizNo(vo.getBizOrderNo());
						line.setOriginBizNo(StringUtils.isBlank(vo.getBizOrderNo())?vo.getNoticeNo():vo.getBizOrderNo());
						//line.setOriginBizLineNo(vo.getBizOrderlineNo());
						line.setOriginBizLineNo(StringUtils.isBlank(vo.getBizOrderlineNo())?vo.getNoticeLineNo():vo.getBizOrderlineNo());//考虑资产手动新增通知单的情况
						line.setSort(vo.getSort());
						if(StringUtils.isNotBlank(vo.getLotNo())){
							line.setLotNo(vo.getLotNo());
							line.setSubLotIndex(vo.getSubLotIndex());
							if (StringUtils.equals("in",notice.getAccessType())){
								String subLotIndex = StringUtils.isBlank(vo.getSubLotIndex())?"0":vo.getSubLotIndex();
								LotKey lotKey = new LotKey();
								lotKey.setLotNo(vo.getLotNo());
								lotKey.setSubLotIndex(subLotIndex);
								Lot dbLot = JpaUtil.getOne(Lot.class, lotKey);
								if (dbLot==null){//保存批次
									Lot lot = new Lot();
									lot.setLotNo(vo.getLotNo());
									lot.setLotStatus(LotStatusUtil.toBinaryString("0"));
									lot.setSubLotIndex("0");
									JpaUtil.save(lot);
									line.setSubLotIndex(lot.getSubLotIndex());
								}else{
									line.setSubLotIndex(dbLot.getSubLotIndex());
								}
							}
						}else if(context.getLotService() == null){
							line.setLotNo("none");
						}else{
							if (!(StringUtils.equals(notice.getPickingType(), NoticeStatusEnums.NoticeType.TO_IN.getCode()))&&StringUtils.equals("in",notice.getAccessType())){//指定出入类型，控制通知单执行逻辑中，是否需要生成批次（排除调拨入）
								Lot newLot = context.getLotService().getNewLot(notice, vo, typesMap);
								if (newLot!=null){
									line.setLotNo(newLot.getLotNo());
									line.setSubLotIndex(newLot.getSubLotIndex());
								}else{
									line.setLotNo("none");
									line.setSubLotIndex("0");
								}
							}
						}
						line.setOriginNoticeNo(notice.getNoticeNo());
						line.setOriginNoticeLineNo(vo.getNoticeLineNo());
						JpaUtil.save(line);
					}
				}
			}else{
				WarehouseOrder wo = null;
				int lineNo = 0;
				List<BizNoticeType> bizNoticeTypes = JpaUtil.linq(BizNoticeType.class).list();
				Map<String, BizNoticeType> typesMap = JpaUtil.index(bizNoticeTypes);
				for(OrderExcuteLineVo vo : orderExcuteVos){
					lineNo++;
					if(wo == null){
						wo = new WarehouseOrder();
						wo.setAccessType(notice.getAccessType());
						wo.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());
						wo.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
						wo.setOrderStatus(OrderStatusEnums.OrderStatus.PLAN.getStatusCode());
						wo.setOrderDate(new Date());
						wo.setOriginBizNo(StringUtils.isBlank(vo.getBizOrderNo())?vo.getNoticeNo():vo.getBizOrderNo());//20221012 wpp 如果是由手工录入的通知单（物资系统操作），那么此处bizOrderNo会为空
						wo.setWhCode(vo.getWhCode());
						wo.setWoType(notice.getPickingType());
						wo.setOriginNoticeNo(notice.getNoticeNo());//关联noticeno字段
						JpaUtil.save(wo);
					}
					WarehouseOrderLine line = new WarehouseOrderLine();
					line.setWhCode(wo.getWhCode());
					line.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
					Item item = JpaUtil.linq(Item.class).idEqual(vo.getItemCode()).findOne();
					line.setItemCode(vo.getItemCode());
					line.setItemGroupCode(item.getItemGroupCode());
					line.setItemName(item.getItemName());
					line.setItemSpec(item.getItemSpec());
					line.setUnitCode(item.getUnitCode());
					line.setDrawingNo(item.getDrawingNo());
					line.setQuantity(vo.getQuantity());
					line.setBizNo(wo.getBizNo());
					line.setLineNo(lineNo+"");
					//line.setOriginBizNo(vo.getBizOrderNo());
					line.setOriginBizNo(StringUtils.isBlank(vo.getBizOrderNo())?vo.getNoticeNo():vo.getBizOrderNo());
					//line.setOriginBizLineNo(vo.getBizOrderlineNo());
					line.setOriginBizLineNo(StringUtils.isBlank(vo.getBizOrderlineNo())?vo.getNoticeLineNo():vo.getBizOrderlineNo());//考虑资产手动新增通知单的情况
					line.setSort(vo.getSort());
					if(StringUtils.isNotBlank(vo.getLotNo())){
						line.setLotNo(vo.getLotNo());
						line.setSubLotIndex(vo.getSubLotIndex());
						if (StringUtils.equals("in",notice.getAccessType())){
							String subLotIndex = StringUtils.isBlank(vo.getSubLotIndex())?"0":vo.getSubLotIndex();
							LotKey lotKey = new LotKey();
							lotKey.setLotNo(vo.getLotNo());
							lotKey.setSubLotIndex(subLotIndex);
							Lot dbLot = JpaUtil.getOne(Lot.class, lotKey);
							if (dbLot==null){//保存批次
								Lot lot = new Lot();
								lot.setLotNo(vo.getLotNo());
								lot.setLotStatus(LotStatusUtil.toBinaryString("0"));
								lot.setSubLotIndex("0");
								JpaUtil.save(lot);
								line.setSubLotIndex(lot.getSubLotIndex());
							}else{
								line.setSubLotIndex(dbLot.getSubLotIndex());
							}
						}
					}else if(context.getLotService() == null){
						line.setLotNo("none");
					}else{
						if (!(StringUtils.equals(notice.getPickingType(), NoticeStatusEnums.NoticeType.TO_IN.getCode()))&&StringUtils.equals("in",notice.getAccessType())){//指定出入类型，控制通知单执行逻辑中，是否需要生成批次（排除调拨入）
							Lot newLot = context.getLotService().getNewLot(notice, vo, typesMap);
							if (newLot!=null){
								line.setLotNo(newLot.getLotNo());
								line.setSubLotIndex(newLot.getSubLotIndex());
							}else{
								line.setLotNo("none");
								line.setSubLotIndex("0");
							}
						}
					}
					line.setOriginNoticeNo(notice.getNoticeNo());
					line.setOriginNoticeLineNo(vo.getNoticeLineNo());
					JpaUtil.save(line);
				}
			}
			afterExecute(context);
			notice.setNoticeStatus(NoticeStatusEnums.NoticeStatus.CONFIRM.getStatusCode());
			JpaUtil.update(notice);
		} else {
			if(CollectionUtils.isEmpty(context.getErrors())) {
				context.addError("前置校验不通过");
			}
		}

	}

	@Override
	public NoticeContext config(NoticeContext context) {
		context.setOrderExcuteVos(orderExcuteVos);
		return context;
	}

	@Override
	public boolean beforeExecute(NoticeContext context) {
		Notice notice = context.getEntity();
		Long count = JpaUtil.linq(FeedPlanNotice.class).equal("sourcePickingNoticeNo", notice.getNoticeNo()).count();
		if (count>0){
			context.addError("JIT物料对应的通知单不需要人工确认操作！");
			return false;
		}
		return true;
	}

	@Override
	public void afterExecute(NoticeContext context) {
		
	}

}
